export type IServiceCallback = (data: any)=>void

export default class ServiceListener<T> {
    protected _messageListeners: Map<T, IServiceCallback[]> = new Map()
    protected _onceMessageListeners: Map<T, Map<number, IServiceCallback[]>> = new Map()

    protected handleMessage (cmd: T, data: any, seq?: number): void {
      const map = this._onceMessageListeners.has(cmd) && this._onceMessageListeners.get(cmd)
      if (map && seq && map.has(seq)) {
        const callbacks = map.get(seq) as IServiceCallback[]
        map.delete(seq)
        for (const callback of callbacks) {
          callback(data)
        }
      }

      const array = this._messageListeners.has(cmd) && this._messageListeners.get(cmd)
      if (array) {
        for (const callback of array) {
          callback(data)
        }
      }
    }

    protected onceMessage (cmd: T, seq: number, callback: IServiceCallback): void {
      let map = this._onceMessageListeners.has(cmd) && this._onceMessageListeners.get(cmd)
      if (!map) {
        map = new Map()
        this._onceMessageListeners.set(cmd, map)
      }
      if (map.has(seq)) {
        (<IServiceCallback[]>map.get(seq)).push(callback)
      } else {
        map.set(seq, [callback])
      }
    }

    onMessage (cmd: T, callback: IServiceCallback): void {
      if (this._messageListeners.has(cmd)) {
        let array = this._messageListeners.get(cmd);
        (<IServiceCallback[]>array).push(callback)
      } else {
        this._messageListeners.set(cmd, [callback])
      }
    }

    offMessage (cmd: T, callback: IServiceCallback): void {
      if (!this._messageListeners.has(cmd)) return
      let array = this._messageListeners.get(cmd) as IServiceCallback[]
      const index = array.indexOf(callback)
      if (index < 0) return
      array.splice(index, 1)
    }
}